/*
 * test_main.c
 *
 *  Created on: Apr 14, 2012
 *      Author: zhanggx
 */

#include <check.h>

#include "gx.h"

gx_globals_t gx_globals;

//test for arrays
#define ARRAY_COUNT 10
START_TEST(test_array)
{
	gx_array_t array;
	int i;

	gx_array_init(&array, ARRAY_COUNT, sizeof(gx_int32_t));
	for(i = 0; i < ARRAY_COUNT * 5; i++){
		gx_int32_t* new_elt = gx_array_push(&array);
		*new_elt = i;
	}

	for(i = 0; i < ARRAY_COUNT * 5; i++){
		gx_int32_t* pos = gx_array_get(&array, i);
		fail_unless(pos != NULL);
		fail_unless(*pos == i);
	}
}
END_TEST

Suite*
array_suite(){
	Suite *s = suite_create ("gx_array_suite");

	/* Core test case */
	TCase *tc_core = tcase_create ("array normal");
	tcase_add_test (tc_core, test_array);
	suite_add_tcase (s, tc_core);

	return s;
}

//rbtree functions
#define ESTIMATE_NODE_COUNT 3

void check_and_delete(gx_rbtree_t* tree, int key) {
	gx_array_t node_list;
	gx_array_init(&node_list, ESTIMATE_NODE_COUNT, sizeof(gx_rbtree_node_t *));

	int i;
	gx_rbtree_search(tree, key, &node_list);
	for(i = 0; i < node_list.nelts; i++){
		gx_rbtree_node_t** pnode = gx_array_get(&node_list, i);
		gx_rbtree_delete(tree, *pnode);
	}
	gx_array_destroy(&node_list);
}
void check_and_insert(gx_rbtree_t* tree, int key) {
	gx_rbtree_insert(tree, key, NULL);
}

#define RBTREE_SIZE 2

START_TEST(test_rbtree_search){
	gx_rbtree_node_t node;
	gx_rbtree_t tree;
	gx_rbtree_init(&tree);
	int i;
	for (i = 1; i <= RBTREE_SIZE; i ++) {
		check_and_insert(&tree, i);
	}
	fail_unless(tree.size == RBTREE_SIZE);

	for (i = 1; i <= RBTREE_SIZE; i++){
		gx_array_t node_list;
		gx_array_init(&node_list, ESTIMATE_NODE_COUNT, sizeof(gx_rbtree_node_t *));

		gx_rbtree_search(&tree, i, &node_list);
		fail_unless(node_list.nelts == 1, "assert node_list.nelts(%d) == 1 error",
				node_list.nelts);
		gx_array_destroy(&node_list);
	}

}
END_TEST
//rbtree tests
START_TEST(test_rbtree_unique) {
	gx_rbtree_node_t node;
	gx_rbtree_t tree;
	gx_rbtree_init(&tree);
	int i;
	for (i = 1; i <= RBTREE_SIZE; i ++) {
		check_and_insert(&tree, i);
	}
	fail_unless(tree.size == RBTREE_SIZE);

	for (i = 1; i <= RBTREE_SIZE; i++) {
		check_and_delete(&tree, i);
	}
	fail_unless(tree.size == 0, "ASSERT tree.size(%d) == 0 error", tree.size);
	gx_rbtree_destroy(&tree);
}
END_TEST

START_TEST(test_rbtree_all_same){
	gx_rbtree_node_t node;
	gx_rbtree_t tree;
	gx_rbtree_init(&tree);
	int i;
	for (i = 1; i <= RBTREE_SIZE; i ++) {
		int n = rand()% RBTREE_SIZE;
		check_and_insert(&tree, 1);
	}

	fail_unless(tree.size == RBTREE_SIZE, "Assert tree.size(%d) == %d failed",
			tree.size, RBTREE_SIZE);
	check_and_delete(&tree, 1);
	fail_unless(tree.size == 0);
}
END_TEST

START_TEST(test_rbtree_minimum){
	gx_rbtree_node_t node;
	gx_rbtree_t 	 tree;

	gx_rbtree_init(&tree);
	int i;
	for (i = 1; i <= RBTREE_SIZE; i ++) {
		check_and_insert(&tree, i);
	}
	fail_unless(tree.size == RBTREE_SIZE, "Assert tree.size(%d) == %d failed",
			tree.size, RBTREE_SIZE);
	gx_array_t node_list;
	gx_array_init(&node_list, ESTIMATE_NODE_COUNT, sizeof(gx_rbtree_node_t *));
	gx_rbtree_minimum(&tree, &node_list);

	fail_unless(node_list.nelts == 1, "assert node_list.nelts(%d) == 1 error",
			node_list.nelts);
	gx_rbtree_node_t** new_node = (gx_rbtree_node_t**)gx_array_get(&node_list, 0);
	fail_unless((*new_node)->key == 1);
}
END_TEST

START_TEST(test_rbtree_get_successor){
	#define VERY_BIG_NUMBER 0x7fffffff
	gx_rbtree_node_t node;
	gx_rbtree_t 	 tree;

	gx_rbtree_init(&tree);

	check_and_insert(&tree, 1);
	check_and_insert(&tree, 3);
	check_and_insert(&tree, 5);
	check_and_insert(&tree, VERY_BIG_NUMBER -1);

	gx_array_t node_list;
	gx_array_init(&node_list, ESTIMATE_NODE_COUNT, sizeof(gx_rbtree_node_t *));

	gx_rbtree_search_nearest(&tree, 2, &node_list);
	fail_unless(node_list.nelts == 1, "assert node_list.nelts (%d) == 1 error",
			node_list.nelts);
	gx_rbtree_node_t** new_node = (gx_rbtree_node_t**)gx_array_get(&node_list, 0);
	fail_unless((*new_node)->key == 3,
			"assert new_node key (%d) == %d error", (*new_node)->key,
			3);

	gx_array_destroy(&node_list);
	gx_array_init(&node_list, ESTIMATE_NODE_COUNT, sizeof(gx_rbtree_node_t *));

	gx_rbtree_search_nearest(&tree, 6, &node_list);
	fail_unless(node_list.nelts == 1, "assert node_list.nelts (%d) == 1 error",
			node_list.nelts);
	new_node = (gx_rbtree_node_t**)gx_array_get(&node_list, 0);
	fail_unless((*new_node)->key == VERY_BIG_NUMBER - 1,
			"assert new_node key (%d) == %d error", (*new_node)->key,
			VERY_BIG_NUMBER -1);

	gx_array_destroy(&node_list);
	gx_array_init(&node_list, ESTIMATE_NODE_COUNT, sizeof(gx_rbtree_node_t *));

	gx_rbtree_search_nearest(&tree, VERY_BIG_NUMBER, &node_list);
	fail_unless(node_list.nelts == 1, "assert node_list.nelts (%d) == 1 error",
			node_list.nelts);
	new_node = (gx_rbtree_node_t**)gx_array_get(&node_list, 0);
	fail_unless((*new_node)->key == 1,
			"assert new_node key (%d) == %d error", (*new_node)->key,
			1);

	gx_array_destroy(&node_list);
}
END_TEST


Suite*
rbtree_suite(){
	Suite *s = suite_create ("gx_rbtree_suite");

	TCase *tc_rbtree_search = tcase_create ("rbtree_search");
	tcase_add_test (tc_rbtree_search , test_rbtree_search);
	suite_add_tcase (s, tc_rbtree_search);

	TCase *tc_rbtree_all_same = tcase_create ("rbtree_all_same");
	tcase_add_test (tc_rbtree_all_same, test_rbtree_all_same);
	suite_add_tcase (s, tc_rbtree_all_same);

	TCase *tc_rbtree_unique = tcase_create ("rbtree_unique");
	tcase_add_test (tc_rbtree_unique , test_rbtree_unique);
	suite_add_tcase (s, tc_rbtree_unique);

	TCase *tc_rbtree_min = tcase_create ("rbtree_min");
	tcase_add_test (tc_rbtree_min , test_rbtree_minimum);
	suite_add_tcase (s, tc_rbtree_min);

	TCase *tc_rbtree_successor = tcase_create ("rbtree_min");
	tcase_add_test (tc_rbtree_successor , test_rbtree_get_successor);
	suite_add_tcase (s, tc_rbtree_successor);

	return s;
}


#define INSERT_RING_NODE_COUNT 100000
START_TEST(test_hashring_insert_numours){
	int ret = init_globals(&gx_globals);
	fail_unless(ret == 0);

	gx_hashring_t ring, *g_ring;
	g_ring = gx_globals.g_hashring;
	g_ring->copy_to_ring(g_ring, &ring);

	ring.init_ring(&ring);
	gx_string_t key;
	char* buf;
	int i;

	#define BUF_SIZE 16
	for(i = 0; i < INSERT_RING_NODE_COUNT; i++){
		buf = (char *)gx_malloc(BUF_SIZE);
		snprintf(buf, BUF_SIZE, "%d", i);
		gx_set_string(key, buf);
		ring.add_node(&ring, key, NULL);
	}

	fail_unless(ring.node_tree->size == INSERT_RING_NODE_COUNT);

}
END_TEST

START_TEST(test_hashring_select_node){
	int ret = init_globals(&gx_globals);
	fail_unless(ret == 0);
	gx_hashring_t ring, *g_ring;
	g_ring = gx_globals.g_hashring;
	g_ring->copy_to_ring(g_ring, &ring);

	ring.init_ring(&ring);
	gx_string_t key;
	char* buf;
	int i;

	#define BUF_SIZE 16
	for(i = 0; i < INSERT_RING_NODE_COUNT; i++){
		buf = (char *)gx_malloc(BUF_SIZE);
		snprintf(buf, BUF_SIZE, "%d", i);
		gx_set_string(key, buf);
		ring.add_node(&ring, key, NULL);
	}

	gx_hash_node_t node;
	gx_string_t str_key = gx_new_string("hello");
	ret = ring.select_node_for_key(&ring, &node, str_key);
	fail_unless(ret == 0);


}
END_TEST
Suite*
hashring_suite(){
	Suite *s = suite_create ("gx_rbtree_suite");

	TCase *tc_hashring_insert_numours = tcase_create ("hashring_insert_numours");
	tcase_add_test (tc_hashring_insert_numours, test_hashring_insert_numours);
	suite_add_tcase (s, tc_hashring_insert_numours);

	TCase *tc_hashring_select = tcase_create ("hashring_select");
	tcase_add_test (tc_hashring_select, test_hashring_select_node);
	suite_add_tcase (s, tc_hashring_select);

	return s;
}
int
main(int argc, char** argv){
	int number_failed;
	Suite *s = NULL;
	s = array_suite ();
	SRunner *sr = srunner_create (s);

	s = rbtree_suite();
	srunner_add_suite(sr, s);

	s = hashring_suite();
	srunner_add_suite(sr, s);

	srunner_run_all (sr, CK_VERBOSE);
	number_failed = srunner_ntests_failed (sr);
	srunner_free (sr);
	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
